laravel檔案系統使用 flysystem ,預設可將檔案存在本地端、SFTP或是AWS S3,並可輕鬆切換
config/filesystems.php
php artisan storage:link
這個 Artisan 命令用於創建符號連結,將 config/filesystems.php 內指定的路徑(預設是 public/storage) 連結到 storage/app/public 目錄,讓公開檔案可讓瀏覽器在 public 讀取。
Illuminate\Support\Facades\Storage 有多種方法可以輕易地對檔案進行操作,例如:
League\Flysystem\UnableToWriteFile:
如果嘗試使用 Storage 對檔案進行操作時發生異常,可設定拋出League\Flysystem\UnableToWriteFile 實體。
預設的 disk 被寫在這裡,會套用到 .env 檔案內的設定
/*
|--------------------------------------------------------------------------
| Default Filesystem Disk
|--------------------------------------------------------------------------
*/
'default' => env('FILESYSTEM_DISK', 'local'),
.env 檔案,建議在 .env 檔案改為 public
本地端開發 local 及 public 皆可,專案上線後因為要讓部分檔案可公開讓大家儲存,就會需要改成 public
FILESYSTEM_DISK=public
除了預設的 disk 外,也可在這裡設定自己想要的 disk
/*
|--------------------------------------------------------------------------
| Filesystem Disks
|--------------------------------------------------------------------------
*/
'disks' => [
'local' => [
'driver' => 'local',
'root' => storage_path('app'),
// 檔案會被放在 storage/app 中
'throw' => false,
],
'public' => [
'driver' => 'local',
'root' => storage_path('app/public'),
'url' => env('APP_URL').'/storage',
// 檔案會被放在 storage/app/public
'visibility' => 'public',
'throw' => false,
],
's3' => [ //AWS s3 儲存空間服務
'driver' => 's3',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION'),
'bucket' => env('AWS_BUCKET'),
'url' => env('AWS_URL'),
'endpoint' => env('AWS_ENDPOINT'),
'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false),
'throw' => false,
],
],
可以用 php artisan storage:link
建立連結,建立連結後,無論檔案放在哪個資料夾,都可在另一個資料夾中讀取到
/*
|--------------------------------------------------------------------------
| Symbolic Links
|--------------------------------------------------------------------------
*/
'links' => [
public_path('storage') => storage_path('app/public'),
],
我希望每個團購都能有一張代表圖片,會在首頁、查看團購時顯示,使用者在新增團購時可上傳圖片,如果沒上傳就用預設圖片代替。
前端畫面加入上傳圖片功能, 標籤要加入 enctype="multipart/form-data”
才能傳檔案(使用 bootstrap5,其他前端方法可能不同)
<form action="/group" method="POST" enctype="multipart/form-data">
//...
<div class="mb-3">
<label for="group_image" class="form-label">上傳團購圖片</label>
<input name="group_image" class="form-control"
type="file" id="group_image">
</div>
</form>
GroupController 加入圖片驗證邏輯,將圖片路徑一起存入資料庫
public function store(Request $request)
{
$validated = $request->validate([
'group_name' => 'required|string|min:3|max:50',
'organizer_id' => 'required|int',
'close_price' => 'nullable|decimal:0,2',
'close_date' => 'nullable|date|after_or_equal:today',
'allow_insert_product' => 'nullable',
'status' => 'required|int',
'group_image' =>
'nullable|image|mimes:jpeg,png,jpg,gif|max:2048'
// 加入圖片驗證邏輯
]);
abort_if(
!$validated['close_date'] && !$validated['close_price'],
Response::HTTP_BAD_REQUEST,
__('請設定團購截止條件')
);
if ($validated['group_image']) {
$validated['image_path'] = $validated['group_image']
->store('public/groups');
// 因為 database 裡面只能存路徑,而非存檔案,要把檔案先儲存後取得路徑
} else {
$validated['image_path'] = "揪團囉.png";
// 如果使用者沒有上傳圖片,就給他我預設的檔案路徑
}
$group = Group::create($validated);
// 路徑與資料一起存入資料庫
return redirect(url("/group/$group->id/product/create"));
}
在前端畫面中顯示
//controller
public function create(Group $group)
{
$group['image_path'] = Storage::url($group['image_path']);
// 將路徑用 Storage::url() 轉換為前端可讀取的位置
// dd()結果如圖
return view('group.createProduct', [
'group' => $group,
]);
}
前端畫面加入顯示圖片,就可以正常顯示囉!
// view
<div class="mb-3">
<img src="{{$group->image_path}}" class="rounded img-fluid" alt="group_image">
</div>
公開檔案(例如:前端畫面、圖片、index.php 等檔案),因為需要讓大家都能存取,程式才能正常運作,因此通常統一會放在 public 資料夾內。而其他非公開檔案(如:.env檔案、controller檔案、model 檔案)則不會公開讓所有人可以存取。
public
資料夾是唯讀的,外部用戶無法直接訪問其中的 PHP 或 config 等配置文件,可以減少潛在的安全漏洞風險,並確保只有公開的檔案可以通過網頁瀏覽器訪問。public
資料夾中,使它們可以直接透過瀏覽器訪問,而無需經過應用程序的處理。這對於顯示圖片、JavaScript 文件、CSS 文件等靜態資源非常有用,因為它們可以通過 URL 直接加載,提高了網頁加載速度和性能。public
資料夾中的內容部署到網頁伺服器(如 Apache、Nginx)的根目錄下,這樣您的網站可以立即提供訪問。這樣的佈署過程簡單明瞭。public
資料夾中可以使您的專案組織結構更加清晰和有序。您可以將靜態資源、上傳的檔案等都放在一個地方,易於管理和維護。試想如果惡意使用者拿到你的 .env 檔案,等同於拿到 database 的帳號密碼,可以進資料庫查看會員的所有資料,那個資就完全外洩了!
有興趣的話可以查看自己有上線的網站被訪問紀錄,這是一個在 aws 上的練習專案,已經幾個月沒碰過,但每天還是有很多 http 訪問紀錄,其中包含一些想要獲取 .env 網站的傢伙!(不過也有可能是一些網站的爬蟲等等…)總之,擋下來就對惹!
雖然在某些情況下可能會感到麻煩,但這種方法通常可以提供更好的彈性、性能和安全性。